<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
<script src="https://cdn.bootcss.com/pdf.js/1.9.491/pdf.min.js"></script>

<div id="demo">
    <button v-on:click="selectFile">选择</button>
    <pdfrender :src="src"></pdfrender>
</div> 

<style>
    .mark{
        position: absolute;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        background: rgba(0,0,0,0.7);
    }
    .loading{
        position: absolute;
        top: 0
    }

    .container{
        max-height: 500px;
        overflow-y: auto;
        background:rgb(82, 86, 89);
        padding: 20px;
    }

    .page{
        margin: auto;
        position: relative;
        margin-bottom: 10px;
        box-shadow: 0px 0px 14px 0px black;
    }
</style>


<script type="text/x-template" id="pdf-render-page">
    <div class="page" :style="{width:width + 'px', height:height + 'px'}">
        <canvas :width="width" :height="height" ref="canvas"></canvas>
        <div v-if="state === 0" class="mark">wait loading</div>
        <div v-if="state === 1" class="loading">loading</div>
        <!-- <div v-if="pageRender[index] === 2" class="ok">ok</div> -->
        <div v-if="state === 3" class="error">ok</div>
    </div>
</script>

<script type="text/x-template" id="pdf-render">
    <div>
        <button v-on:click="bigger">变大</button>
        <button v-on:click="smaller">变小</button>
        <div class="container" ref="container" @scroll="scroll">
            <pdfrenderpage v-for="page in pageArr" :page="page" ref="pages" :scale="scale"></pdfrenderpage>
        </div>
    </div>
</script>
<script>
    PDFJS.workerSrc = "https://cdn.bootcss.com/pdf.js/1.9.491/pdf.worker.min.js"

    const CSS_UNITS = 96.0 / 72.0;    
    const VIEW_STATE_WAITE = 0;
    const VIEW_STATE_ING = 1;
    const VIEW_STATE_OK = 2;
    const VIEW_STATE_ERROR = 3;

    Vue.component('pdfrenderpage', {
        template: '#pdf-render-page',
        props:{
            page:{
                required:true
            },
            scale:{
                default:1
            }
        },
        data() {
            return {
                state: VIEW_STATE_WAITE
            }
        },
        computed:{
            viewport() {
                return this.page.getViewport( this.scale)
            },
            width() {
                // return this.viewport.width
                return Math.floor(this.viewport.width)
            },
            height() {
                // return this.viewport.height                
                return Math.floor(this.viewport.height)
            },
        },
        watch:{
            scale(){
                this.init()
            }
        },
        methods:{
            init(){
                this.state = VIEW_STATE_WAITE
            },
            renderPage(){
                let page = this.page
                if(this.state !== VIEW_STATE_WAITE){
                    return
                }
                this.state = VIEW_STATE_ING;

                let bcanvas = document.createElement('canvas')
                let viewport = this.viewport
                let context = bcanvas.getContext('2d')
                bcanvas.height = this.height
                bcanvas.width = this.width

                var renderContext = {
                    canvasContext: context,
                    viewport: viewport
                }
                console.log(renderContext)
                var renderTask = page.render(renderContext);
                renderTask.then(_ => {
                    let canvas = this.$refs.canvas
                    this.state = VIEW_STATE_OK;
                    this.$nextTick(_ => {
                        canvas.getContext('2d').drawImage(bcanvas, 0, 0, this.width, this.height)
                    })
                });
            }
        }
    })


    Vue.component('pdfrender', {
        template: '#pdf-render',
        props:{
            src:{
                type:String,
                required:true
            }
        },
        data() {
            return {
                loadingTask: null,
                pdf: null,
                pagenum: 0,
                pageArr: [],
                scale:1
            }
        },
        computed: {
            pageView() {
                return this.pageArr.map(view => {
                    var viewport = view.page.getViewport(this.scale);
                    return viewport
                })
            }
        },
        watch: {
            src() {
                if(this.src){
                    this.init()
                }
            },
            pageArr(n) {
                console.log(n)
            }
        },
        methods: {
            scroll:scrollExtend({
                scrollEnd:function(e){
                    this.renderPages()
                }
            }),  
            init() {
                this.loadingTask = null
                this.pdf = null
                this.pagenum = 0
                this.pageArr = []

                this.render()
            },
            render() {
                let loadingTask =  PDFJS.getDocument(this.src).promise
                this.loadingTask = loadingTask
                loadingTask.then(this.loaded)
            },
            loaded(pdf) {
                console.info(`pdf loaded !`)
                this.pdf = pdf
                this.pagenum = pdf.numPages

                let parr = []
                for(let i = 1; i <= pdf.numPages; i++){
                    parr.push(pdf.getPage(i))
                }
                Promise.all(parr).then(this.pagesInit)
            },
            pagesInit(pages){
                this.pageArr = pages
                this.$nextTick(this.renderPages)
            },
            renderPages(){
                let container = this.$refs.container
                let pages = this.$refs.pages

                let crect = container.getBoundingClientRect()
                pages.forEach((page, index) => {
                    let rect = page.$el.getBoundingClientRect()
                    if(rect.top < crect.bottom && rect.bottom > crect.top){
                        page.renderPage()
                    }
                })
            },
            bigger() {
                this.scale = this.scale + 0.1
                this.$nextTick(this.renderPages)
            },
            smaller() {
                this.scale = this.scale - 0.1
                this.$nextTick(this.renderPages)
            }
        }
    })


    let x = new Vue({
        el:"#demo",
        data:{
            inputE:null,
            src:""
        },
        methods:{
            selectFile(){
                let input = document.createElement("input")
                input.type = "file"
                input.click()
                input.onchange = this.getFile
                this.inputE = input
            },
            getFile() {
                let file = this.inputE.files[0]
                var reader = new FileReader()
                let data = reader.readAsDataURL(file)

                reader.onload = _ => {
                    this.src = reader.result
                    // this.src = "http://127.0.0.1/outputs/test.pdf"
                }
            }
        }
    })

    function scrollExtend(options){
        let handler=null;
        let {
            scrollStart,
            scrollIng,
            scrollEnd,
            delay = 200
        } = options

        return function(){
            let _arguments = arguments
            if(!handler&&scrollStart) scrollStart.apply(this, _arguments)
            if(handler) clearTimeout(handler)
            if(scrollIng) scrollIng.apply(this, _arguments)
            if(scrollEnd){
                handler = setTimeout(()=>{
                    handler = null
                    scrollEnd.apply(this, _arguments)
                },delay)
            }
        };
    }

    function getOutputScale(ctx) {
        let devicePixelRatio = window.devicePixelRatio || 1;
        let backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                                ctx.mozBackingStorePixelRatio ||
                                ctx.msBackingStorePixelRatio ||
                                ctx.oBackingStorePixelRatio ||
                                ctx.backingStorePixelRatio || 1;
        let pixelRatio = devicePixelRatio / backingStoreRatio;
        return {
            sx: pixelRatio,
            sy: pixelRatio,
            scaled: pixelRatio !== 1,
        };
    }

</script>